# include "jam.h"
# include "newstr.h"
# include "lists.h"
#include "alloc.h"

static ALLOC *listalloc = 0;

static LIST *freelist = 0;

LIST * list_append( LIST  *l, LIST  *nl ) {
  if( !nl ) {
  } else if( !l ) {
    l = nl;
  } else {
    l->tail->next = nl;
    l->tail = nl->tail;
  }
  return l;
}

LIST * list_new( LIST  *head, const char *string, int copy ) {
  LIST *l;
  if( DEBUG_LISTS ) {
    printf( "list > %s <\n", string );
  }
  string = copy ? copystr( string ) : newstr( string );
  if( freelist ) {
    l = freelist;
    freestr( l->string );
    freelist = freelist->next;
  } else {
    if( !listalloc ) {
      listalloc = alloc_init( sizeof( LIST ), 64 );
    }
    l = ( LIST * ) alloc_enter( listalloc );
  }
  if( !head ) {
    head = l;
  } else {
    head->tail->next = l;
  }
  head->tail = l;
  l->next = 0;
  l->string = string;
  return head;
}

LIST * list_copy( LIST  *l, LIST  *nl ) {
  for( ; nl; nl = list_next( nl ) ) {
    l = list_new( l, nl->string, 1 );
  }
  return l;
}

LIST * list_sublist( LIST  *l, int start, int count ) {
  LIST  *nl = 0;
  for( ; l && start--; l = list_next( l ) ) ;
  for( ; l && count--; l = list_next( l ) ) {
    nl = list_new( nl, l->string, 1 );
  }
  return nl;
}

void list_free( LIST  *head ) {
  if( head ) {
    head->tail->next = freelist;
    freelist = head;
  }
}

void list_print( LIST *l ) {
  for( ; l; l = list_next( l ) ) {
    printf( "%s ", l->string );
  }
}

void list_printq( FILE *out, LIST *l ) {
  for( ; l; l = list_next( l ) ) {
    const char *p = l->string;
    const char *ep = p + strlen( p );
    const char *op = p;
    fputc( '\n', out );
    fputc( '\t', out );
    fputc( '"', out );
    while( ( p = ( char * )memchr( op, '"',  ep - op ) ) ) {
      fwrite( op, p - op, 1, out );
      fputc( '\\', out );
      fputc( '"', out );
      op = p + 1;
    }
    fwrite( op, ep - op, 1, out );
    fputc( '"', out );
    fputc( ' ', out );
  }
}

int list_length( LIST *l ) {
  int n = 0;
  for( ; l; l = list_next( l ), ++n )
    ;
  return n;
}

void lol_init( LOL *lol ) {
  lol->count = 0;
}

void lol_add( LOL *lol, LIST  *l ) {
  if( lol->count < LOL_MAX ) {
    lol->list[ lol->count++ ] = l;
  }
}

void lol_free( LOL *lol ) {
  int i;
  for( i = 0; i < lol->count; i++ ) {
    list_free( lol->list[i] );
  }
  lol->count = 0;
}

LIST * lol_get( LOL *lol, int i ) {
  return i < lol->count ? lol->list[i] : 0;
}

void lol_print( LOL *lol ) {
  int i;
  for( i = 0; i < lol->count; i++ ) {
    if( i ) {
      printf( " : " );
    }
    list_print( lol->list[i] );
  }
}

void donelist( void ) {
  freelist = 0;
  alloc_free( listalloc );
  listalloc = 0;
}
